
cmake_minimum_required (VERSION 2.6)
project (acquire)

option(DOWNLOAD_NEW_KEYS "Download and install new broker keys to the key database automatically" ON)
option(BUILD_STATIC "Build in library code from static libraries" OFF)
option(BUILD_STATIC_LIBRARIES "Build static Acquire library" OFF)

set(DYNAMIC_LINKER "/lib64/ld-linux-x86-64.so.2" CACHE STRING "Dynamic linker definition for portability")

set(CMAKE_CXX_IGNORE_EXTENSIONS 1)

if ( CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR )
   message( STATUS "${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}" )
   message( FATAL_ERROR "You must run CMake in a different directory to the source!" )
endif ( CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR )

# Define default host and port for broker in a new header file
set(DEFAULT_HOST ssi-amrmmhd.epcc.ed.ac.uk)
#set(DEFAULT_HOST 127.0.0.1)
set(DEFAULT_PORT 10000)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/default_hosts.h "\n#ifndef __DEFAULT_HOSTS_H\n")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/default_hosts.h "#define __DEFAULT_HOSTS_H\n\n")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/default_hosts.h "#define DEFAULT_HOST \"")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/default_hosts.h ${DEFAULT_HOST})
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/default_hosts.h "\"\n#define DEFAULT_PORT_STRING \"")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/default_hosts.h ${DEFAULT_PORT})
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/default_hosts.h "\"\n#define DEFAULT_PORT ")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/default_hosts.h ${DEFAULT_PORT})
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/default_hosts.h "\n\n#endif\n")
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/config.h "\n#ifndef __CONFIG_H\n")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/config.h "#define __CONFIG_H\n\n")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/config.h "#define ACQUIRE_STATIC_DIR \"")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/config.h ${ACQUIRE_STATIC_DATA_DIR})
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/config.h "\"\n#define ACQUIRE_DYNAMIC_DIR \"")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/config.h ${ACQUIRE_DYNAMIC_DATA_DIR})
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/config.h "\"\n\n#endif\n")

# Make sure to include the new header file in the compilation
include_directories(${CMAKE_CURRENT_BINARY_DIR})

set(SAVED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
if (BUILD_STATIC)
   set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nodefaultlibs -Wl,--hash-style=both --hash-style=sysv -fPIC -Wl,-dynamic-linker,${DYNAMIC_LINKER} -L.")
else (BUILD_STATIC)
   set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--hash-style=both --hash-style=sysv -fPIC -Wl,-dynamic-linker,${DYNAMIC_LINKER} -L. -Wl,-rpath-link,'$ORIGIN' -Wl,-rpath,'$ORIGIN'")
endif (BUILD_STATIC)
# SET THIS ON WHEN USING MAC OS
if (APPLE)
   set(CMAKE_EXE_LINKER_FLAGS "")
endif (APPLE)

# Probably want a special switch to turn this off!
set(BROKERKEY ${CMAKE_CURRENT_BINARY_DIR}/brokerkey)
set(BROKERKEYNAME ${CMAKE_CURRENT_BINARY_DIR}/brokerkeyname)

if ( DOWNLOAD_NEW_KEYS )
   file(REMOVE ${BROKERKEYNAME} ${BROKERKEY})
   file(WRITE ${BROKERKEYNAME} "broker")
endif ( DOWNLOAD_NEW_KEYS )

file(READ ${BROKERKEYNAME} KEYID)

if ( DOWNLOAD_NEW_KEYS )
   file(DOWNLOAD http://${DEFAULT_HOST}:${DEFAULT_PORT}/hosted_files/${KEYID}.pub ${BROKERKEY} SHOW_PROGRESS STATUS STATVARBKEY)
   if ( NOT STATVARBKEY EQUAL 0 )
      message ( FATAL_ERROR "Could not download broker key ${STATVARBKEY}" )
   endif ( NOT STATVARBKEY EQUAL 0 )
endif ( DOWNLOAD_NEW_KEYS )

set (CMAKE_BUILD_TYPE Debug)

set (CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)

if (BUILD_STATIC)
   exec_program(${CMAKE_CXX_COMPILER} ${CMAKE_CURRENT_SOURCE_DIR} ARGS -print-file-name=libgcc_eh.a OUTPUT_VARIABLE LIBGCC_LIBRARY)
   exec_program(${CMAKE_CXX_COMPILER} ${CMAKE_CURRENT_SOURCE_DIR} ARGS -print-file-name=libstdc++.a OUTPUT_VARIABLE LIBSTDCXX_LIBRARY)
   set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
   message(STATUS "STATIC LIBRARIES...")
else (BUILD_STATIC)
   message(STATUS "LIBRARIES...")
endif (BUILD_STATIC)

find_package(LibXml2)
find_package(cryptlib)
find_package(Sqlite3)
find_package(Valgrind)
find_package(LibSSH2)

if (BUILD_STATIC)
   set(CMAKE_FIND_LIBRARY_SUFFIXES .so)
   message(STATUS "SHARED LIBRARIES...")

   find_package(ZLIB)
   find_package(Threads)
   find_library(LIBPTHREAD_LIBRARY NAMES pthread)
   find_library(LIBDL_LIBRARY NAMES dl)
   find_library(LIBM_BUILTIN_M NAMES m)
   find_library(LIBC_BUILTIN_C NAMES c)

   if (CMAKE_USE_PTHREADS_INIT)
      message(STATUS "Found libpthread: ${LIBPTHREAD_LIBRARY}")
   else (CMAKE_USE_PTHREADS_INIT)
      message(FATAL_ERROR "Could not find libpthread")
   endif (CMAKE_USE_PTHREADS_INIT)

   if (LIBDL_LIBRARY)
      message(STATUS "Found libdl: ${LIBDL_LIBRARY}")
   else (LIBDL_LIBRARY)
      message(FATAL_ERROR "Could not find libdl")
   endif (LIBDL_LIBRARY)

   if (ZLIB_FOUND)
      message(STATUS "Found zlib: ${ZLIB_LIBRARIES}")
   else (ZLIB_FOUND)
      message(FATAL_ERROR "Could not find zlib")
   endif (ZLIB_FOUND)
endif (BUILD_STATIC)

find_package(APR)
find_package(OpenSSL)
find_library(LIBCRYPTO_LIBRARY NAMES crypto)

if (LIBCRYPTO_LIBRARY)
   message(STATUS "Found libcrypto: ${LIBCRYPTO_LIBRARY}")
else (LIBCRYPTO_LIBRARY)
   message(FATAL_ERROR "Could not find libcrypto")
endif (LIBCRYPTO_LIBRARY)

set (INCLUDE_DIRS )
set (DEFINES )

if (LIBXML2_FOUND)
  set (INCLUDE_DIRS ${INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIR})
else (LIBXML2_FOUND)
  message ( FATAL_ERROR "Could not find Libxml2" )
endif (LIBXML2_FOUND)

if (CRYPTLIB_FOUND)
  set (INCLUDE_DIRS ${INCLUDE_DIRS} ${CRYPTLIB_INCLUDE_DIR})
else (CRYPTLIB_FOUND)
  message ( FATAL_ERROR "Could not find cryptlib" )
endif (CRYPTLIB_FOUND)

if (APR_FOUND)
  set (INCLUDE_DIRS ${INCLUDE_DIRS} ${APR_INCLUDE_DIR})
else (APR_FOUND)
  message ( FATAL_ERROR "Could not find apr" )
endif (APR_FOUND)

if (APRUTIL_FOUND)
   set (INCLUDE_DIRS ${INCLUDE_DIRS} ${APRUTIL_INCLUDE_DIR})
else (APRUTILS_FOUND)
   message ( FATAL_ERROR "Could not find aprutils" )
endif (APRUTIL_FOUND)

if (OPENSSL_FOUND)
   set (INCLUDE_DIRS ${INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR})
else (OPENSSL_FOUND)
   message ( FATAL_ERROR "Could not find OpenSSL" )
endif (OPENSSL_FOUND)

if (SQLITE3_FOUND)
   set (INCLUDE_DIRS ${INCLUDE_DIRS} ${SQLITE3_INCLUDE_DIR})
else (SQLITE3_FOUND)
   message ( FATAL_ERROR "Could not find Sqlite3" )
endif (SQLITE3_FOUND)

if (LIBSSH2_FOUND)
   set (INCLUDE_DIRS ${INCLUDE_DIRS} ${LIBSSH2_INCLUDE_DIR})
else (LIBSSH2_FOUND)
   message ( FATAL_ERROR "Could not find LibSSH2" )
endif (LIBSSH2_FOUND)

if (VALGRIND_FOUND)
   set (INCLUDE_DIRS ${INCLUDE_DIRS} ${VALGRIND_INCLUDE_DIR})
   add_definitions ( "-DVALGRIND_HACKS" )
   add_definitions ( "-DPURIFY" )
endif (VALGRIND_FOUND)

#add_definitions ( "-DPASSDEFINE" "-D_GNU_SOURCE" )

include_directories(${INCLUDE_DIRS})

if ( NOT LIBSSH2_VERSION_MAJOR GREATER 1 AND LIBSSH2_VERSION_MINOR LESS 3 )
   message ( FATAL_ERROR "LibSSH2 is too old (needed LibSSH2 >= 1.3, got LibSSH2 ${LIBSSH2_VERSION}" )
endif ( NOT LIBSSH2_VERSION_MAJOR GREATER 1 AND LIBSSH2_VERSION_MINOR LESS 3 )

set ( ACQUIRE_LIB_SOURCES
       aprtools/APRBucketBrigade.cpp
       aprtools/APRTable.cpp
       aprtools/APRPRNG.cpp
       crypt/AESSymmetricKey.cpp
       crypt/CryptEChain.cpp
       crypt/DecryptWrapper.cpp
       crypt/EncryptWrapper.cpp
       crypt/RSAKeyPairGenerator.cpp
       crypt/DSAKeyPairGenerator.cpp
       crypt/ECDSAKeyPairGenerator.cpp
       crypt/Key.cpp
       crypt/KeyPair.cpp
       crypt/PublicKey.cpp
       crypt/PrivateKey.cpp
       crypt/SymmetricKey.cpp
       crypt/RSAKeyPair.cpp
       crypt/RSAPublicKey.cpp
       crypt/RSAPrivateKey.cpp
       crypt/DSAPublicKey.cpp
       crypt/DSAPrivateKey.cpp
       crypt/ECDSAPublicKey.cpp
       crypt/ECDSAPrivateKey.cpp
       db/ActorsDB.cpp
       db/ClusterSSHDB.cpp
       db/DBArbitrator.cpp
       db/KeyDB.cpp
       db/KeyTableView.cpp
       db/NewActorsDB.cpp
       db/NewKeyDB.cpp
       db/PendingDB.cpp
       db/SQLiteDB.cpp
       iface/APRInterface.cpp
       iface/CryptInterface.cpp
       iface/LibSSH2Interface.cpp
       iface/SSLInterface.cpp
       iface/SQLiteInterface.cpp
       iface/XMLInterface.cpp
       net/Broker4Client.cpp
       net/Broker4Server.cpp
       net/Broker4.cpp
       net/BrokerMessage.cpp
       net/EncMessage.cpp
       net/ForwardServer.cpp
       net/HTTPServer.cpp
       net/SSHChain.cpp
       net/SSHClient.cpp
       net/TCPClient.cpp
       net/TCPServer.cpp
       utils/BaseConvert.cpp
       utils/Hash.cpp
       utils/Prompt.cpp
       utils/RunningWorkProcess.cpp
       utils/SerialBlockSink.cpp
       utils/SerialBlockSource.cpp
       utils/StreamFromDirectory.cpp
       utils/StreamToDirectory.cpp
       utils/StringUtils.cpp
       xml/DOMDocument.cpp
       xml/XMLDescriptor.cpp
       xml/XMLReader.cpp
       xml/XMLWriter.cpp
       acquire_client.cpp
    )

set ( BROKER_SOURCES
       main_broker.cpp
    )

set ( NEWCLIENT_SOURCES
      acquire_client.cpp
      main_newclient.cpp
    )

set ( COMPUTE_SOURCES
       main_compute.cpp
    )

set ( GLIBCPATCH_SOURCES
       isoc99_sscanf_glibc_patch.c
    )

set (LINK_LIBRARIES )

if (LIBXML2_FOUND)
  set (LINK_LIBRARIES ${LINK_LIBRARIES} ${LIBXML2_LIBRARIES})
endif (LIBXML2_FOUND)

if (CRYPTLIB_FOUND)
  set (LINK_LIBRARIES ${LINK_LIBRARIES} ${CRYPTLIB_LIBRARIES})
endif (CRYPTLIB_FOUND)

if (APR_FOUND)
  set (LINK_LIBRARIES ${LINK_LIBRARIES} ${APR_LIBRARY})
endif (APR_FOUND)

if (APRUTIL_FOUND)
   set (LINK_LIBRARIES ${LINK_LIBRARIES} ${APRUTIL_LIBRARY})
endif (APRUTIL_FOUND)

if (SQLITE3_FOUND)
   set (LINK_LIBRARIES ${LINK_LIBRARIES} ${SQLITE3_LIBRARY_DEBUG})
endif (SQLITE3_FOUND)

if (LIBSSH2_FOUND)
   set (LINK_LIBRARIES ${LINK_LIBRARIES} ${LIBSSH2_LIBRARY})
endif (LIBSSH2_FOUND)

if (OPENSSL_FOUND)
   set (LINK_LIBRARIES ${LINK_LIBRARIES} ${OPENSSL_LIBRARIES} ${LIBCRYPTO_LIBRARY})
endif (OPENSSL_FOUND)

if (BUILD_STATIC_LIBRARIES)
   add_library(glibcpatch ${GLIBCPATCH_SOURCES})
   target_link_libraries(glibcpatch)
   add_library(Acquire STATIC ${ACQUIRE_LIB_SOURCES})
else (BUILD_STATIC_LIBRARIES)
   add_library(Acquire SHARED ${ACQUIRE_LIB_SOURCES})
endif (BUILD_STATIC_LIBRARIES)

if (BUILD_STATIC)
   find_library(LIBCRYPT_LIBRARY NAMES crypt)
   find_library(LIBFREEBL3_LIBRARY NAMES freebl3)
   find_library(LIBRT_LIBRARY NAMES rt)
   find_library(LIBEXPAT_LIBRARY NAMES expat)

   add_library(zlib SHARED IMPORTED)
   set_property(TARGET zlib PROPERTY IMPORTED_LOCATION ${ZLIB_LIBRARY})
   add_library(libpthread SHARED IMPORTED)
   set_property(TARGET libpthread PROPERTY IMPORTED_LOCATION ${LIBPTHREAD_LIBRARY})
   add_library(libdl SHARED IMPORTED)
   set_property(TARGET libdl PROPERTY IMPORTED_LOCATION ${LIBDL_LIBRARY})
   add_library(libm SHARED IMPORTED)
   set_property(TARGET libm PROPERTY IMPORTED_LOCATION ${LIBM_BUILTIN_M})
   add_library(libc SHARED IMPORTED)
   set_property(TARGET libc PROPERTY IMPORTED_LOCATION ${LIBC_BUILTIN_C})
   target_link_libraries(Acquire ${LINK_LIBRARIES} glibcpatch zlib libpthread libdl libm libc ${LIBSTDCXX_LIBRARY} ${LIBGCC_LIBRARY})
else (BUILD_STATIC)
   if (BUILD_STATIC_LIBRARIES)
      target_link_libraries(Acquire ${LINK_LIBRARIES} glibcpatch)
   else (BUILD_STATIC_LIBRARIES)
      target_link_libraries(Acquire ${LINK_LIBRARIES})
   endif (BUILD_STATIC_LIBRARIES)
endif (BUILD_STATIC)

add_executable(genkeydb genkeydb.cpp)
target_link_libraries(genkeydb Acquire)

add_executable(acquirea ${BROKER_SOURCES})
target_link_libraries(acquirea Acquire)

execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory hosted_files)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/bootstrap.sh.in ${CMAKE_CURRENT_BINARY_DIR}/hosted_files/bootstrap.sh)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/queue.sh.in ${CMAKE_CURRENT_BINARY_DIR}/hosted_files/queue.sh)

if ( DOWNLOAD_NEW_KEYS )
   add_custom_target(KEYDB DEPENDS genkeydb)
   add_custom_command(
      TARGET KEYDB
      DEPENDS genkeydb
      COMMAND ${CMAKE_CURRENT_BINARY_DIR}/genkeydb ARGS brokerkeyname brokerkey
   )
endif ( DOWNLOAD_NEW_KEYS )

add_executable(newclient ${NEWCLIENT_SOURCES})
if ( DOWNLOAD_NEW_KEYS )
   add_dependencies(newclient KEYDB)
endif ( DOWNLOAD_NEW_KEYS )
target_link_libraries(newclient Acquire)

execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory results_files)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory workarea_files)

add_executable(compute ${COMPUTE_SOURCES})
target_link_libraries(compute Acquire)

add_custom_command(
   TARGET compute
   POST_BUILD
   COMMAND ${CMAKE_COMMAND} -E copy compute hosted_files/compute
)

# Name of executable install dir
set (ACQUIRE_BIN "bin")
# Shared library install dir
set (ACQUIRE_LIBS "lib")
# Static library install dir
set (ACQUIRE_ARCHIVES "lib/static")
# Include (header) files install dir
set (ACQUIRE_INCLUDES "include/Acquire")
# Shared files that stay static
set (ACQUIRE_FILES "share/Acquire")
# CMake install files install dir
set (ACQUIRE_CMAKEFILES "include/Acquire/cmake")

install( TARGETS Acquire newclient compute acquirea EXPORT AcquireLibrary
           RUNTIME DESTINATION ${ACQUIRE_BIN}
           LIBRARY DESTINATION ${ACQUIRE_LIBS}
           ARCHIVE DESTINATION ${ACQUIRE_ARCHIVES}
       )
       
install( FILES ${CMAKE_CURRENT_SOURCE_DIR}/acquire_client.h
         DESTINATION ${ACQUIRE_INCLUDES} )

install( FILES ${CMAKE_CURRENT_BINARY_DIR}/default_hosts.h
         DESTINATION ${ACQUIRE_INCLUDES} )

install( FILES "${CMAKE_CURRENT_BINARY_DIR}/hosted_files/brokerkeyname"
               "${CMAKE_CURRENT_BINARY_DIR}/hosted_files/broker.pub"
               "${CMAKE_CURRENT_BINARY_DIR}/hosted_files/bootstrap.sh"
               "${CMAKE_CURRENT_BINARY_DIR}/hosted_files/queue.sh"
               "${CMAKE_CURRENT_BINARY_DIR}/hosted_files/compute"
         DESTINATION ${ACQUIRE_FILES}/hosted_files/ )

install( EXPORT AcquireLibrary
         NAMESPACE Acquire_
         DESTINATION ${ACQUIRE_CMAKEFILES} )
